//
// Created by Chen qin lang on 2018/7/6.
//

#include "WlFFmpeg.h"

WlFFmpeg::WlFFmpeg(WlPlayStat *playStat, JavaCall *call, const char *url) : playStats(playStat),
                                                                            call(call), url(url) {
    pthread_mutex_init(&decode_mutex, NULL);
    pthread_mutex_init(&seek_mutex, NULL);
}

void *decodeFFmpeg(void *context) {
    WlFFmpeg *fFmpeg = (WlFFmpeg *) context;
    fFmpeg->decodeThread();
    pthread_exit(&fFmpeg->pthread_play);
}

int avformat_callback(void *context) {
    WlFFmpeg *wlFFmpeg = (WlFFmpeg *) context;
    if (wlFFmpeg->playStats->isexit) {
        LOGE("wlffmpeg true")
        return AVERROR_EOF;
    }
    return 0;

}

void WlFFmpeg::decodeThread() {
    pthread_mutex_lock(&decode_mutex);
    int ret;
    av_register_all();
    avformat_network_init();
    pFormatContext = avformat_alloc_context();

    pFormatContext->interrupt_callback.callback = avformat_callback;
    pFormatContext->interrupt_callback.opaque = this;

    if (ret = avformat_open_input(&pFormatContext, url, NULL, NULL) < 0) {
        call->onError(CHILD_THREAD);
        LOGE("avformat_open_input failed %s", av_err2str(ret))
        isexit = true;
        pthread_mutex_unlock(&decode_mutex);
        return;
    }
    if (ret = avformat_find_stream_info(pFormatContext, NULL) < 0) {
        call->onError(CHILD_THREAD);
        LOGE("avformat_find_stream_info failed %s", av_err2str(ret))
        isexit = true;
        pthread_mutex_unlock(&decode_mutex);
        return;
    }
    for (int i = 0; i < pFormatContext->nb_streams; i++) {
        if (pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            if (audio == NULL) {
                audio = new WlAudio(i, playStats, pFormatContext->streams[i]->codecpar->sample_rate,
                                    call);
                audio->codecpar = pFormatContext->streams[i]->codecpar;
                audio->duration = pFormatContext->duration / AV_TIME_BASE;
                audio->timebase = pFormatContext->streams[i]->time_base;
                duration = audio->duration;

            }
        }
    }
    AVCodec *pCodec = avcodec_find_decoder(audio->codecpar->codec_id);
    if (!pCodec) {
        call->onError(CHILD_THREAD);
        isexit = true;
        pthread_mutex_unlock(&decode_mutex);
        return;
    }
    audio->codecCtx = avcodec_alloc_context3(pCodec);
    ret = avcodec_parameters_to_context(audio->codecCtx, audio->codecpar);
    if (ret < 0) {
        call->onError(CHILD_THREAD);
        LOGE("avformat_find_stream_info failed %s", av_err2str(ret))
        isexit = true;
        pthread_mutex_unlock(&decode_mutex);
        return;
    }
    if (ret = avcodec_open2(audio->codecCtx, pCodec, NULL)) {
        call->onError(CHILD_THREAD);
        LOGE("avformat_find_stream_info failed %s", av_err2str(ret))
        isexit = true;
        pthread_mutex_unlock(&decode_mutex);
        return;
    }
    call->onPrepared(CHILD_THREAD);

    pthread_mutex_unlock(&decode_mutex);

}

void WlFFmpeg::prepared() {
    pthread_create(&pthread_play, NULL, decodeFFmpeg, this);//4 参数指针
}

void WlFFmpeg::start() {
    if (audio == NULL) {
        LOGE("audio is null");
        return;;
    }

    int /*count = 0, */ret;

    audio->play();
    while (playStats != NULL && !playStats->isexit) {
        if (playStats->seek) {
            av_usleep(1000*100);
            continue;
        }
        if (audio->queue->getAvpacketSize() > 100) {
            av_usleep(1000*100);
            continue;
        }
        AVPacket *avPacket = av_packet_alloc();
        pthread_mutex_lock(&seek_mutex);
        ret = av_read_frame(pFormatContext, avPacket);//同步读取数据包,防止数据包多线程错乱
        pthread_mutex_unlock(&seek_mutex);
        if (ret == 0) {
            if (avPacket->stream_index == audio->streamIndex) {
                audio->queue->putAvpacket(avPacket);
                /*   count++;
                   LOGE("解码第 %d 帧", count);*/

            } else {
                av_free_packet(avPacket);
                av_free(avPacket);
                avPacket = NULL;

            }

        } else {

            av_free_packet(avPacket);
            av_free(avPacket);
            avPacket = NULL;
            //解码完成时,查看队列中是否完成将状态改为退出
            while (playStats != NULL && !playStats->isexit) {
                if (audio->queue->getAvpacketSize() > 0) {
                    av_usleep(1000*100);
                    continue;
                } else {
                    playStats->isexit = true;
                }
            }
            LOGE("av_read_frame failed %s", av_err2str(ret));
            break;
        }
    }
    if (call != NULL) {
        call->onCallComplete(CHILD_THREAD);
    }
    isexit = true;
    /* while (audio->queue->getAvpacketSize() > 0) {
         AVPacket *avPacket11 = av_packet_alloc();
         LOGE("av_packet_alloc %p", avPacket11);
         audio->queue->getAvpacket(avPacket11);
         LOGE("getAvpacket");
         av_free_packet(avPacket11);
         av_free(avPacket11);
         avPacket11 = NULL;
         if (audio->queue->getAvpacketSize()==0)break;
     }*/
    LOGE("解码完成")


}

void WlFFmpeg::resume() {
    if (audio != NULL) {
        audio->resume();
    }

}

void WlFFmpeg::pause() {
    if (audio != NULL) {
        audio->pause();
    }
}

void WlFFmpeg::release() {

    playStats->isexit = true;
    pthread_mutex_lock(&decode_mutex);
    int sleep_conut;
    //当ffmpeg解析未完成,延时10秒结束
    while (!isexit) {
        if (sleep_conut > 1000) {
            isexit = true;
        }
        LOGE("sleep frame count %2d", sleep_conut);
        sleep_conut++;
        av_usleep(1000 * 10);
    }
    if (audio != NULL) {
        audio->release();
        delete (audio);
        audio = NULL;
        LOGE("release_audio");
    }
    if (pFormatContext != NULL) {
        avformat_close_input(&pFormatContext);
        avformat_free_context(pFormatContext);
        pFormatContext = NULL;
        LOGE("release_pFormatContext");
    }
    if (playStats != NULL) {
        playStats = NULL;
        LOGE("release_playStats");
    }
    if (call != NULL) {
        call = NULL;
        LOGE("release_call");
    }
    pthread_mutex_unlock(&decode_mutex);


}

WlFFmpeg::~WlFFmpeg() {
    pthread_mutex_destroy(&decode_mutex);
    pthread_mutex_destroy(&seek_mutex);
}

void WlFFmpeg::seek(int seconds) {
    if (duration > 0) {
        if (seconds >= 0 && seconds < duration) {
            playStats->seek = true;
            audio->queue->clearQueue();//清空缓存
            pthread_mutex_lock(&seek_mutex);
            //将解码时间戳归置为o 避免重复累加
            audio->now_time = 0;
            audio->clock = 0;
            audio->last_time = 0;
            int64_t time = seconds * AV_TIME_BASE;
            avformat_seek_file(pFormatContext, -1, INT64_MIN, time, INT64_MAX, 0);
            pthread_mutex_unlock(&seek_mutex);
            playStats->seek = false;
        }
    }


}

void WlFFmpeg::setVolume(int process) {
    if (audio != NULL) {
        audio->setVolume(process);
    }
}

void WlFFmpeg::setMuter(int channels) {
    if (audio!=NULL) {
     audio->setMuter(channels);
    }
}

void WlFFmpeg::setTempo(float tempo) {
    if (audio!=NULL){
        audio->setTempo(tempo);
    }
}

void WlFFmpeg::setPitch(float pitch) {
    if (audio!=NULL){
        audio->setPitch(pitch);
    }

}
